import {
  Controller,
  Get,
  Post,
  Body,
  Patch,
  Param,
  Delete,
  Inject,
  Query,
  BadRequestException,
  UnauthorizedException,
  Headers,
} from '@nestjs/common';
import { QrcodeLoginService } from './qrcode-login.service';
import { CreateQrcodeLoginDto } from './dto/create-qrcode-login.dto';
import { UpdateQrcodeLoginDto } from './dto/update-qrcode-login.dto';
import { randomUUID } from 'crypto';
import * as qrcode from 'qrcode';
import { RedisService } from '../redis/redis.service';
import { JwtService } from '@nestjs/jwt';

interface QrCodeInfo {
  status:
    | 'noscan'
    | 'scan-wait-confirm'
    | 'scan-confirm'
    | 'scan-cancel'
    | 'expired';
  userInfo?: {
    userId: number;
  };
}
// noscan 未扫描
// scan-wait-confirm -已扫描，等待用户确认
// scan-confirm 已扫描，用户同意授权
// scan-cancel 已扫描，用户取消授权
// expired 已过期

@Controller('qrcode-login')
export class QrcodeLoginController {
  constructor(private readonly qrcodeLoginService: QrcodeLoginService) {}

  @Inject(RedisService)
  private redisService: RedisService;

  @Inject(JwtService)
  private jwtService: JwtService;

  @Get('qrcode/generate')
  async generate() {
    const uuid = randomUUID();
    const dataUrl = await qrcode.toDataURL(
      `http://192.168.43.218:3002/static/confirm.html?id=${uuid}`,
    );
    this.redisService.hashSet(`qrcode_${uuid}`, { status: 'noscan' });
    return {
      qrcode_id: uuid,
      img: dataUrl,
    };
  }

  @Get('qrcode/check')
  async check(@Query('id') id: string) {
    return this.redisService.hashGet(`qrcode_${id}`);
  }

  @Get('qrcode/scan')
  async scan(@Query('id') id: string) {
    const info = await this.redisService.hashGet(`qrcode_${id}`);
    if (!info) {
      throw new BadRequestException('二维码已过期');
    }
    info.status = 'scan-wait-confirm';
    this.redisService.hashSet(`qrcode_${id}`, info);
    return 'success';
  }

  @Get('qrcode/confirm')
  async confirm(@Query('id') id: string, @Headers('Authorization') auth: string) {
    let user;
    try{
      const [, token] = auth.split(' ');
      
      const info = await this.jwtService.verify(token);

      user = this.users.find(item => item.id == info.userId);
    } catch(e) {
      throw new UnauthorizedException('token 过期，请重新登录');

    }
    const info = await this.redisService.hashGet(`qrcode_${id}`);
    if (!info) {
      throw new BadRequestException('二维码已过期');
    }
    info.status = 'scan-confirm';
    info.userId = user.id;
    info.username = user.username
    this.redisService.hashSet(`qrcode_${id}`, info);
    return 'success';
  }

  @Get('qrcode/cancel')
  async cancel(@Query('id') id: string) {
    const info = await this.redisService.hashGet(`qrcode_${id}`);
    if (!info) {
      throw new BadRequestException('二维码已过期');
    }
    info.status = 'scan-cancel';
    this.redisService.hashSet(`qrcode_${id}`, info);
    return 'success';
  }

  private users = [
    { id: 1, username: 'dong', password: '111' },
    { id: 2, username: 'guang', password: '222' },
  ];

  @Get('login')
  async login(
    @Query('username') username: string,
    @Query('password') password: string,
  ) {
    const user = this.users.find((item) => item.username === username);

    if (!user) {
      throw new UnauthorizedException('用户不存在');
    }
    if (user.password !== password) {
      throw new UnauthorizedException('密码错误');
    }

    return {
      token: await this.jwtService.sign({
        userId: user.id,
      }),
    };
  }

  @Get('userInfo')
  async userInfo(@Headers('authorization') auth: string) {
    try {
      const [, token] = auth.split(' ');
      const info = await this.jwtService.verify(token);

      const user = this.users.find((item) => item.id == info.userId);
      // return user;
    } catch (e) {
      throw new UnauthorizedException('token 过期，请重新登录');
    }
  }

  @Post()
  create(@Body() createQrcodeLoginDto: CreateQrcodeLoginDto) {
    return this.qrcodeLoginService.create(createQrcodeLoginDto);
  }

  @Get()
  findAll() {
    return this.qrcodeLoginService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.qrcodeLoginService.findOne(+id);
  }

  @Patch(':id')
  update(
    @Param('id') id: string,
    @Body() updateQrcodeLoginDto: UpdateQrcodeLoginDto,
  ) {
    return this.qrcodeLoginService.update(+id, updateQrcodeLoginDto);
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.qrcodeLoginService.remove(+id);
  }
}
